package cn.piesat.config;

import cn.piesat.util.JedisUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import reactor.core.publisher.Mono;
import redis.clients.jedis.Jedis;

import java.util.*;

/**
 * 权限控制管理器
 *
 * @author xhl
 */
@Component
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {

    private Logger logger = LoggerFactory.getLogger(AuthorizationManager.class);

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
        ServerHttpRequest request = authorizationContext.getExchange().getRequest();
        String path = request.getURI().getPath();
        PathMatcher pathMatcher = new AntPathMatcher();
        //跨域直接放行
        if (request.getMethod() == HttpMethod.OPTIONS) {
            return Mono.just(new AuthorizationDecision(true));
        }
        Jedis jedis = JedisUtils.getJedis();
        try {
            //校验白名单
            if (jedis != null) {
                Map<String, String> whiteMap = jedis.hgetAll("auth:whiteList");
                Set<String> paths = whiteMap.keySet();
                for (String pattern : paths) {
                    if (pathMatcher.match(pattern,path)) {
                        return Mono.just(new AuthorizationDecision(true));
                    }
                }
                //token为空拒绝放行
                String token = request.getHeaders().getFirst("Authorization");
                if (StringUtils.isBlank(token)) {
                    return Mono.just(new AuthorizationDecision(false));
                }
                Map<String, String> resourceRolesMap = jedis.hgetAll("auth:resourceRoles");
                Iterator<String> iterator = resourceRolesMap.keySet().iterator();
                //请求路径匹配到的资源需要的角色权限集合authorities统计
                List<String> authorities = new ArrayList<>();
                while (iterator.hasNext()) {
                    String pattern = iterator.next();
                    if (pathMatcher.match(pattern,path)) {
                        JSONObject js = JSONObject.parseObject(resourceRolesMap.get(pattern));
                        authorities.addAll(JSON.parseArray(js.getString("markList"),String.class));
                    }
                }
                return mono
                        .filter(Authentication::isAuthenticated)
                        .flatMapIterable(Authentication::getAuthorities)
                        .map(GrantedAuthority::getAuthority)
                        .any(authorities::contains)
                        .map(AuthorizationDecision::new)
                        .defaultIfEmpty(new AuthorizationDecision(false));
            }
        }catch(Exception e) {
            logger.error("权限控制管理器出现错误->{}", e);
        }finally {
            JedisUtils.close(jedis);
        }
        return Mono.just(new AuthorizationDecision(false));
    }

}
